using System;
using System.Runtime.InteropServices;

using Dashboard;
using Dashboard.Engine;

using Wnck;

namespace Dashboard.Engine.Backends
{
	public class ContextTrackerBackend : IComponent
	{
		private delegate void Callback ();

		private Screen screen;

		public string Name
		{
			get { return "ContextTracker"; }
		}

		public string Description
		{
			get { return "Tracks the context of user activity"; }
		}

		public void Initialize ()
		{
			// FIXME: We probably need to do something
			// special here with regard to Xinerama and
			// such, but I dont have a setup available.
			
			screen = Screen.Default;
			
			screen.ActiveWindowChanged += OnActiveWindowChanged;

			screen.WindowOpened += OnWindowOpened;
			screen.WindowClosed += OnWindowClosed;

			screen.ActiveWorkspaceChanged += OnActiveWorkspaceChanged;
			
			screen.ApplicationOpened += OnApplicationOpened;
			screen.ApplicationClosed += OnApplicationClosed;
		}
		
		public void Dispose ()
		{
			screen.ActiveWindowChanged -= OnActiveWindowChanged;
			
			screen.WindowOpened -= OnWindowOpened;
			screen.WindowClosed -= OnWindowClosed;
			
			screen.ActiveWorkspaceChanged -= OnActiveWorkspaceChanged;
			
			screen.ApplicationOpened -= OnApplicationOpened;
			screen.ApplicationClosed -= OnApplicationClosed;
		}
		
		private void OnActiveWindowChanged (object o, EventArgs args)
		{
			// FIXME: As a workaround for a bug in wnck-sharp 
			// that prevents us from using (Screen).ActiveWindow,
			// we need to pinvoke directly into libwnck. This
			// goes bananas sometimes when you switch windows
			// too fast or do anything else strange, but we always 
			// get the correct event and window eventually.
			
			/*IntPtr window_handle = wnck_screen_get_active_window (screen.Handle);
			
			if (window_handle == IntPtr.Zero)
				return;
			*/
			
			Window window = screen.ActiveWindow;

			if (window == null)
				return;

			//Console.WriteLine (window.Xid);
			
			/*ContextMessage context_message = new ContextMessage ();
			context_message.Path= "/context/window/changed";
			context_message.Window = new ContextMessage.ContextWindow (wnck_window_get_xid (window_handle), "");

			IntPtr workspace_handle = wnck_window_get_workspace (window_handle);
			if (workspace_handle != IntPtr.Zero)
				context_message.Workspace = wnck_workspace_get_number (workspace_handle);
			
			IntPtr application_handle = wnck_window_get_application (window_handle);
			if (application_handle != IntPtr.Zero) {
				int application_xid = wnck_application_get_xid (application_handle);
				string application_name = Marshal.PtrToStringAnsi (wnck_application_get_name (application_handle));
				
				context_message.Application = new ContextMessage.ContextApplication (application_xid, application_name);
			}												     
			
			Engine.MessageBroker.Send (context_message);*/
		}
		
		private void OnWindowOpened (object o, WindowOpenedArgs args)
		{
			Window window = args.Window;
			
			if (window == null)
				return;
			
			/*ContextMessage context_message = new ContextMessage ();
			context_message.Path = "/context/window/opened";
			context_message.Window = new ContextMessage.ContextWindow ((int) window.Xid, window.Name);
			
			if (window.Application != null)
				context_message.Application = new ContextMessage.ContextApplication ((int) window.Application.Xid,
																					 window.Application.Name);
			if (window.Workspace != null)
				context_message.Workspace = window.Workspace.Number;
			
				Engine.MessageBroker.Send (context_message);*/
		}
		
		private void OnWindowClosed (object o, WindowClosedArgs args)
		{
			Window window = args.Window;
			
			if (window == null)
				return;
			
			/*ContextMessage context_message = new ContextMessage ();
			context_message.Path = "/context/window/closed";
			context_message.Window = new ContextMessage.ContextWindow ((int) window.Xid, window.Name);
			
			if (window.Application != null)
				context_message.Application = new ContextMessage.ContextApplication ((int) window.Application.Xid,
																					 window.Application.Name);
			if (window.Workspace != null)
				context_message.Workspace = window.Workspace.Number;
			
				Engine.MessageBroker.Send (context_message);*/
		}
		
		private void OnActiveWorkspaceChanged (object o, EventArgs args)
		{
			// FIXME: Implement
		}

		private void OnApplicationOpened (object o, ApplicationOpenedArgs args)
		{
			// FIXME: Implement
		}

		private void OnApplicationClosed (object o, ApplicationClosedArgs args)
		{
			// FIXME: Implement			
		}

		// FIXME: Remove this once somebody fix the bugs
		// in wnck-sharp.

		[DllImport("libwnck-1")]
		static extern IntPtr wnck_screen_get_active_window (IntPtr screen);

		[DllImport("libwnck-1")]
		static extern int wnck_window_get_xid (IntPtr raw);

		[DllImport ("libwnck-1")]
		static extern IntPtr wnck_window_get_workspace (IntPtr window);

		[DllImport("libwnck-1")]
		static extern int wnck_workspace_get_number (IntPtr workspace);

		[DllImport ("libwnck-1")]
		static extern IntPtr wnck_window_get_application (IntPtr window);

		[DllImport ("libwnck-1")]
		static extern int wnck_application_get_xid (IntPtr application);

		[DllImport ("libwnck-1")]
		static extern IntPtr wnck_application_get_name (IntPtr application);
	}
}